package com.zjpavt.client.hal.network;

import com.zjpavt.client.util.FileUtil;
import com.zjpavt.client.util.LoggerUtil;
import com.zjpavt.client.util.PropertiesUtil;
import io.netty.util.concurrent.DefaultThreadFactory;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 网络流量统计
 * @author zyc
 */
@Slf4j
public class NetworkReceiveAndSendBytes {
    /**
     * 从当前文件中获取的数据
     */
    private static HashMap<String, ReceiveAndTransmitDataCount> receiveAndTransmitDataCountHashMap = new HashMap<>();
    private static long lastUpdateTime;
    private static ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1, new DefaultThreadFactory("ReceiveAndSendBytes"));
    private static final Pattern INTERFACE_NETWOR_DATA_PATTERN = Pattern.compile("(?<interface>[^:]*):\\s*(?<receiveBytes>[0-9]+)" +
            "\\s*(?<receivePactets>[0-9]+)\\s*(?<receiveErrorPackets>[0-9]+)\\s*(?<receiveDropPackets>[0-9]+)\\s*(?<receiveFifo>[0-9]+)" +
            "\\s*(?<receiveFrame>[0-9]+)\\s*(?<receiveCompressed>[0-9]+)\\s*(?<receiveMulticast>[0-9]+)" +
            "\\s*(?<transmitBytes>[0-9]+)\\s*(?<transmitPactets>[0-9]+)\\s*(?<transmitErrorPackets>[0-9]+)\\s*(?<transmitDropPackets>[0-9]+)" +
            "\\s*(?<transmitFifo>[0-9]+)\\s*(?<transmitFrame>[0-9]+)\\s*(?<transmitCompressed>[0-9]+)\\s*(?<transmitMulticast>[0-9]+)");
    static {

    }
    public static HashMap<String, ReceiveAndTransmitDataCount> getCurrentReceiveAndTransmitBytes(String filePath) {
        lastUpdateTime = System.currentTimeMillis();
        try {
            String dataFromFile = FileUtil.readFromFile(filePath);
            String[] everyInterfaceDataMessages = dataFromFile.split("\n");
            for (String interfaceDataMessage :
                    everyInterfaceDataMessages) {
                Matcher matcher = INTERFACE_NETWOR_DATA_PATTERN.matcher(interfaceDataMessage);
                if (matcher.find()) {
                    String interfaceName = matcher.group("interface").trim();
                    long receiveBytes = Long.parseLong(matcher.group("receiveBytes"));
                    long transmitBytes = Long.parseLong(matcher.group("transmitBytes"));
                    receiveAndTransmitDataCountHashMap.put(interfaceName, new ReceiveAndTransmitDataCount(receiveBytes, transmitBytes));
                    if (NetworkManager.getInstance().containNetwork(interfaceName)) {
                        NetworkManager.getInstance().getNetworkMap().get(interfaceName).setCountReceiveAndTransmit(receiveBytes + transmitBytes);
                    }
                    log.debug(matcher.group("interface").trim() + ":" + matcher.group("receiveBytes"));
                } else {
                    log.debug(interfaceDataMessage);
                }
            }
            save2File();
        } catch (IOException e) {
            return null;
        }
        return null;
    }

    /**
     * 获取固件端设备流量信息
     */
    public static void updateNetwork() {
        getCurrentReceiveAndTransmitBytes("/proc/net/dev");

    }

    /**
     * 开始统计接口流量数据任务
     * 周期为每分钟一次
     */
    public static void startDataCountTask() {
        scheduledThreadPoolExecutor.scheduleAtFixedRate(() -> {
            updateNetwork();
        }, 0,1, TimeUnit.MINUTES);
    }

    public static void main(String[] args) {
        getCurrentReceiveAndTransmitBytes("C:\\idea\\svn\\PavtFirmware\\out\\artifacts\\PavtFirmware\\dev");
    }

    public static final String configFileNamePath = "/pavt/conf/dataCount/";

    public static final String DAY_CACHE_KEY = "dayCache";
    public static final String DAY_COUNT_KEY = "dayCount";
    public static final String MONTH_COUNT_KEY = "monthCount";
    public static final DecimalFormat df = new DecimalFormat("00");

    /**
     * 将当天流量缓存到文件中
     */
    private static void save2File() {
        Calendar calendar = Calendar.getInstance();
        String year = String.valueOf(calendar.get(Calendar.YEAR));
        String month = df.format(calendar.get(Calendar.MONTH) + 1);
        String day = String.valueOf(calendar.get(Calendar.DAY_OF_MONTH));
        String fileName = year + month + ".properties";
        File file = new File(configFileNamePath + fileName);
        String configFileName = "dataCount/" + fileName;
        FileUtil.makeSureFileExist(file);
        Map<String,AbstractNetwork> networkMap= NetworkManager.getInstance().getNetworkMap();
        if (networkMap.containsKey(NetworkManager.INTERFACE_PPP_0)) {
            AbstractNetwork network = networkMap.get(NetworkManager.INTERFACE_PPP_0);
            try {
                String sDayCache = PropertiesUtil.getProperties(configFileName, DAY_CACHE_KEY + day);
                if (sDayCache != null) {
                    long lDayCache = Long.parseLong(sDayCache);
                    long countNowByIfconfig = network.getCountReceiveAndTransmit();
                    if (lDayCache < countNowByIfconfig) {
                        PropertiesUtil.setPropertyOrReplace(configFileName, DAY_CACHE_KEY + day, network.getCountReceiveAndTransmit2String());
                    } else if (lDayCache > countNowByIfconfig) {
//                        如果当前网络连接数据量小于文件缓存 则认为是一个新的连接统计
                        PropertiesUtil.setPropertyOrReplace(configFileName, DAY_CACHE_KEY + day, network.getCountReceiveAndTransmit2String());
                        String sDayCount = PropertiesUtil.getProperties(configFileName, DAY_COUNT_KEY + day);
                        long lDayCount = 0;
                        if (sDayCount == null) {
                            log.error("without dayCount dayCache=" + lDayCache);
//                            PropertiesUtil.setPropertyOrReplace(configFileName, DAY_COUNT_KEY + day, String.valueOf(lDayCount));
                        } else {
                            lDayCount = Long.parseLong(sDayCount);
                        }
                        PropertiesUtil.setPropertyOrReplace(configFileName, DAY_COUNT_KEY + day, String.valueOf(lDayCache + lDayCount));
                        clearUpDataCount(configFileName);
                    } else {
//                        两者相等的时候不需要处理
                    }
                } else {
//                    这是新的一天
                    String sDayCount = PropertiesUtil.getProperties(configFileName, DAY_COUNT_KEY + day);
                    if (sDayCount == null) {
                        PropertiesUtil.setPropertyOrReplace(configFileName, DAY_COUNT_KEY + day, String.valueOf(0 - network.getCountReceiveAndTransmit()));
                    }
                    PropertiesUtil.setPropertyOrReplace(configFileName, DAY_CACHE_KEY + day, network.getCountReceiveAndTransmit2String());
                    clearUpDataCount(configFileName);
                }
            } catch (IOException e) {
                log.error(LoggerUtil.convertException2String(e));
            }
        }
    }

    public static final Pattern DATA_CACHE_PATTERN = Pattern.compile("dayCache(?<day>[0-9]+)");
    /**
     * 整理当月的流量数据统计
     */
    private static void clearUpDataCount(String configFileName) {
        long monthCount = 0;
        Set<String> propertiesKeySet = PropertiesUtil.getPropertiesKeySet(configFileName);
        try {
            for (String dataCache :propertiesKeySet) {
                Matcher matcher = DATA_CACHE_PATTERN.matcher(dataCache);
                if (matcher.matches()) {
                    int day = Integer.parseInt(matcher.group("day"));
                    String sDayCache = PropertiesUtil.getProperties(configFileName, DAY_CACHE_KEY + day);
                    String sDayCount = PropertiesUtil.getProperties(configFileName, DAY_COUNT_KEY + day);
                    if (sDayCount != null) {
                        if (sDayCache != null && !"0".equals(sDayCache)) {
                            long dayCount = Long.parseLong(sDayCache) + Long.parseLong(sDayCount);
                            PropertiesUtil.setPropertyOrReplace(configFileName, DAY_COUNT_KEY + day, String.valueOf(dayCount));
                            PropertiesUtil.setPropertyOrReplace(configFileName, DAY_CACHE_KEY + day, String.valueOf(0));
                            monthCount += dayCount;
                        } else {
                            monthCount += Long.parseLong(sDayCount);
                        }
                    } else {
                        log.error("can't catch sDayCache or sDayCount. File path is" + configFileName);
                    }
                }
            }
            PropertiesUtil.setPropertyOrReplace(configFileName, MONTH_COUNT_KEY, String.valueOf(monthCount));
        } catch (IOException e) {
            log.error(LoggerUtil.convertException2String(e));
        }
    }

    public static long getMonthCount() {
        Calendar calendar = Calendar.getInstance();
        String year = String.valueOf(calendar.get(Calendar.YEAR));
        String month = df.format(calendar.get(Calendar.MONTH) + 1);
        String fileName = year + month + ".properties";
        try {
            String monthCount = PropertiesUtil.getProperties(fileName, MONTH_COUNT_KEY);
            if (monthCount != null) {
                return Long.parseLong(month);
            }
        } catch (IOException e) {
            log.error(LoggerUtil.convertException2String(e));
        }
        return 0;
    }
    /**
     * 单网口收发数据对象
     */
    public static class ReceiveAndTransmitDataCount {
        private long receiveDataByte;
        private long transmitDataByte;

        public ReceiveAndTransmitDataCount(long receiveDataByte, long transmitDataByte) {
            this.receiveDataByte = receiveDataByte;
            this.transmitDataByte = transmitDataByte;
        }

        public long getReceiveDataByte() {
            return receiveDataByte;
        }

        public void setReceiveDataByte(long receiveDataByte) {
            this.receiveDataByte = receiveDataByte;
        }

        public long getTransmitDataByte() {
            return transmitDataByte;
        }

        public void setTransmitDataByte(long transmitDataByte) {
            this.transmitDataByte = transmitDataByte;
        }
    }
}
